package TS::Descriptor;

use strict;
use Scalar::Util qw(weaken);

use constant DESC_NULL => 0x00;
use constant DESC_CONDITIONAL_ACCESS => 0x09;
use constant DESC_SHORT_EVENT => 0x4D;
use constant DESC_CONTENT => 0x54;
use constant DESC_DIGITAL_COPY_CONTROL => 0xC1;
use constant DESC_CONTENT_AVAILABILITY => 0xDE;
use constant DESC_STREAM_IDENTIFIER => 0x52;
use constant DESC_DATA_COMPONENT => 0xFD;
use constant DESC_SERVICE => 0x48;
use constant DESC_LOGO_TRANSMISSION => 0xCF;

sub new {
	my($pkg, $buffer) = @_;

	my $hash = {
		buffer => $buffer,
	};

	my $s = bless $hash, $pkg;

	weaken($s->{buffer});

	return $s;
}

sub parse {
	my($buffer) = @_;

	my $s = TS::Descriptor->new($buffer);
	return $s->descriptor();
}

sub descriptor {
	my($s) = @_;

	my $ret = {};

	my $descriptor_tag = $s->{buffer}->getInt();

	if ($descriptor_tag == DESC_SHORT_EVENT) {
		$ret = $s->short_event();
	} elsif ($descriptor_tag == DESC_CONTENT) {
		$ret = $s->content();
	} elsif ($descriptor_tag == DESC_SERVICE) {
		$ret = $s->service();
	} elsif ($descriptor_tag == DESC_DIGITAL_COPY_CONTROL) {
		$ret = $s->dump();
	} elsif ($descriptor_tag == DESC_CONTENT_AVAILABILITY) {
		$ret = $s->dump();
	} elsif ($descriptor_tag == DESC_STREAM_IDENTIFIER) {
		$ret = $s->dump();
	} elsif ($descriptor_tag == DESC_DATA_COMPONENT) {
		$ret = $s->dump();
	} elsif ($descriptor_tag == DESC_LOGO_TRANSMISSION) {
		$ret = $s->dump();
	} elsif ($descriptor_tag == DESC_CONDITIONAL_ACCESS) {
		$ret = $s->dump();
	} elsif ($descriptor_tag == DESC_NULL) {
		# null data
	} else {
		printf "#### no support descriptor_tag: 0x%02x\n", $descriptor_tag;
#		exit;
	}

	$ret->{descriptor_tag} = $descriptor_tag;

	return $ret;
}

sub short_event {
	my($s) = @_;

	my $ret = {};

	$ret->{descriptor_length} = $s->{buffer}->getInt();
	$ret->{ISO_639_language_code} = $s->{buffer}->getBytes(3);

	$ret->{event_name_length} = $s->{buffer}->getInt();
	$ret->{event_name_char} = $s->{buffer}->getBytes($ret->{event_name_length});

	$ret->{text_length} = $s->{buffer}->getInt();
	$ret->{text_char} = $s->{buffer}->getBytes($ret->{text_length});

	return $ret;
}

sub content {
	my($s) = @_;

	my $ret = {};

	$ret->{descriptor_length} = $s->{buffer}->getInt();
	my $descriptor_endbyte = $s->{buffer}->{pos} + $ret->{descriptor_length};

	$ret->{genre} = [];

	while ($s->{buffer}->{pos} + 1 < $descriptor_endbyte) {
		push(@{$ret->{genre}}, $s->content_genre());
	}

	return $ret;
}

sub content_genre {
	my($s) = @_;

	my $ret = {};

	my $a = $s->{buffer}->getInt();
	$ret->{content_nibble_level_1} = $a >> 4 & 0x0F;
	$ret->{content_nibble_level_2} = $a      & 0x0F;

	my $a = $s->{buffer}->getInt();
	$ret->{user_nibble_1} = $a >> 4 & 0x0F;
	$ret->{user_nibble_2} = $a      & 0x0F;

	return $ret;
}

sub service {
	my($s) = @_;

	my $ret = {};

	$ret->{descriptor_length} = $s->{buffer}->getInt();
	$ret->{service_type} = $s->{buffer}->getInt();

	$ret->{service_provider_name_length} = $s->{buffer}->getInt();
	$ret->{service_provider_name_char} = $s->{buffer}->getBytes($ret->{service_provider_name_length});

	$ret->{service_name_length} = $s->{buffer}->getInt();
	$ret->{service_name_char} = $s->{buffer}->getBytes($ret->{service_name_length});

	return $ret;
}

sub dump {
	my($s) = @_;

	my $ret = {};

	$ret->{descriptor_length} = $s->{buffer}->getInt();
	$ret->{descriptor_data} = $s->{buffer}->getBytes($ret->{descriptor_length});

	return $ret;
}

1;
